#ifndef NFI_NET_MODULE_H
#define NFI_NET_MODULE_H

#include <iostream>
#include <iosfwd>
#include "IModule.h"
#include "ILogModule.h"
#include "IPluginManager.h"
#include "INet.h"
#include "GUID.h"
#include "Protocol/Protocol.h"

#ifdef _MSC_VER
#pragma warning(disable: 4244 4267)
#endif

namespace FragrantGrass
{
	enum FG_SERVER_TYPES
	{
		FG_ST_NONE = 0,    // NONE
		FG_ST_REDIS = 1,    //
		FG_ST_MYSQL = 2,    //
		FG_ST_MASTER = 3,    //
		FG_ST_LOGIN = 4,    //
		FG_ST_PROXY = 5,    //
		FG_ST_GAME = 6,    //
		FG_ST_WORLD = 7,    //
		FG_ST_DB = 8,    //
		FG_ST_MAX = 9,    //
	};


	////////////////////////////////////////////////////////////////////////////

	//only use this macro when u has entered game server
//#define CLIENT_MSG_PROCESS(nMsgID, msgData, nLen, msg)                 \
//    GUID nPlayerID;                                \
//    msg xMsg;                                           \
//    if (!NFINetModule::ReceivePB(nMsgID, msgData, nLen, xMsg, nPlayerID))             \
//    {                                                   \
//        m_pLogModule->LogNormal(NFILogModule::NLL_ERROR_NORMAL, GUID(), "", "Parse msg error", __FUNCTION__, __LINE__); \
//        return;                                         \
//    }                                                   \
//    \
//    NF_SHARE_PTR<NFIObject> pObject = m_pKernelModule->GetObject(nPlayerID); \
//    if ( NULL == pObject.get() )                        \
//    {                                                   \
//        m_pLogModule->LogNormal(NFILogModule::NLL_ERROR_NORMAL, nPlayerID, "FromClient Object do not Exist", "", __FUNCTION__, __LINE__); \
//        return;                                         \
//    }
//
//#define CLIENT_MSG_PROCESS_NO_OBJECT(nMsgID, msgData, nLen, msg)                 \
//    GUID nPlayerID;                                \
//    msg xMsg;                                           \
//    if (!NFINetModule::ReceivePB(nMsgID, msgData, nLen, xMsg, nPlayerID))             \
//    {                                                   \
//        m_pLogModule->LogNormal(NFILogModule::NLL_ERROR_NORMAL, GUID(), "", "Parse msg error", __FUNCTION__, __LINE__); \
//        return;                                         \
//    }
//
//#define CLIENT_MSG_PROCESS_NO_LOG(nMsgID, msgData, nLen, msg)                 \
//    GUID nPlayerID;                                \
//    msg xMsg;                                           \
//    if (!NFINetModule::ReceivePB(nMsgID, msgData, nLen, xMsg, nPlayerID))             \
//    {                                                   \
//        return 0;                                         \
//    }

//////////////////////////////////////////////////////////////////////////
	struct ServerData
	{
		ServerData()
		{
			pData = FG_SHARE_PTR<Protocol::ServerInfoReport>(FG_NEW Protocol::ServerInfoReport());
			nFD = 0;
		}
		~ServerData()
		{
			nFD = 0;
			pData = NULL;
		}

		SOCK nFD;
		FG_SHARE_PTR<Protocol::ServerInfoReport> pData;

		static const char* get_server_type_name(int type)
		{
			static const char* g_server_name[(int)FG_ST_MAX] =
			{
				"invalid_server",
				"redis_server",
				"mysql_server",
				"master_server",
				"login_server",
				"proxy_server",
				"game_server",
				"world_server",
				"db_server",
			};
			int index = (int)type;
			if (index < 0 || index >= (int)FG_ST_MAX)
				index = 0;
			return g_server_name[index];
		}

		static const char* get_server_type_name(FG_SERVER_TYPES eServerType)
		{
			return get_server_type_name((int)eServerType);
		}
	};

	class INetModule
		: public IModule
	{
		DECLARE_MODULE_NAME(INetModule)
	public:
		static GUID PBToFG(Protocol::Ident xID)
		{
			GUID  xIdent;
			xIdent.nHead64 = xID.serverid();
			xIdent.nData64 = xID.index();

			return xIdent;
		}

		//static NFVector2 PBToNF(NFMsg::Vector2 value)
		//{
		//	NFVector2  vector;
		//	vector.SetX(value.x());
		//	vector.SetY(value.y());
		//	return vector;
		//}

		//static NFVector3 PBToNF(NFMsg::Vector3 value)
		//{
		//	NFVector3  vector;
		//	vector.SetX(value.x());
		//	vector.SetY(value.y());
		//	vector.SetZ(value.z());
		//	return vector;
		//}

		static Protocol::Ident FGToPB(GUID xID)
		{
			Protocol::Ident  xIdent;
			xIdent.set_serverid(xID.nHead64);
			xIdent.set_index(xID.nData64);

			return xIdent;
		}

		//static NFMsg::Vector2 NFToPB(NFVector2 value)
		//{
		//	NFMsg::Vector2  vector;
		//	vector.set_x(value.X());
		//	vector.set_y(value.Y());
		//	return vector;
		//}

		//static NFMsg::Vector3 NFToPB(NFVector3 value)
		//{
		//	NFMsg::Vector3  vector;
		//	vector.set_x(value.X());
		//	vector.set_y(value.Y());
		//	vector.set_z(value.Z());
		//	return vector;
		//}

		template<typename BaseType>
		bool register_net_message_handler(const int nMsgID, BaseType* pBase, void (BaseType::* handleRecieve)(SOCK, int, const char*, const uint32_t))
		{
			NET_MESSAGE_HANDLER_FUNCTOR functor = std::bind(handleRecieve, pBase, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3, std::placeholders::_4);
			NET_MESSAGE_HANDLER_FUNCTOR_PTR functorPtr(new NET_MESSAGE_HANDLER_FUNCTOR(functor));

			return register_net_message_handler(nMsgID, functorPtr);
		}

		template<typename BaseType>
		bool register_net_message_handler(BaseType* pBase, void (BaseType::* handleRecieve)(SOCK, int, const char*, const uint32_t))
		{
			NET_MESSAGE_HANDLER_FUNCTOR functor = std::bind(handleRecieve, pBase, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3, std::placeholders::_4);
			NET_MESSAGE_HANDLER_FUNCTOR_PTR functorPtr(new NET_MESSAGE_HANDLER_FUNCTOR(functor));

			return register_net_message_handler(functorPtr);
		}

		template<typename BaseType>
		bool register_net_event_handler(BaseType* pBase, void (BaseType::* handler)(const SOCK fd, FG_NET_EVENT nEvent, INet* pNet))
		{
			NET_EVENT_HANDLER_FUNCTOR functor = std::bind(handler, pBase, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3);
			NET_EVENT_HANDLER_FUNCTOR_PTR functorPtr(new NET_EVENT_HANDLER_FUNCTOR(functor));

			return register_net_event_handler(functorPtr);
		}

		static bool recieve_protobuf_message(const int nMsgID, const char* msg, const uint32_t nLen, std::string& strMsg, GUID& nPlayer)
		{
			Protocol::MsgBase xMsg;
			if (!xMsg.ParseFromArray(msg, nLen))
			{
				char szData[MAX_PATH] = { 0 };
				FGSPRINTF(szData, MAX_PATH, "Parse Message Failed from Packet to MsgBase, MessageID: %d\n", nMsgID);
#ifdef DEBUG
				std::cout << "--------------------" << szData << __FUNCTION__ << " " << __LINE__ << std::endl;
#endif // DEBUG

				return false;
			}

			strMsg.assign(xMsg.msg_data().data(), xMsg.msg_data().length());

			nPlayer = PBToFG(xMsg.player_id());

			return true;
		}

		static bool recieve_protobuf_message(const int nMsgID, const std::string& strMsgData, google::protobuf::Message& xData, GUID& nPlayer)
		{
			return recieve_protobuf_message(nMsgID, strMsgData.c_str(), (uint32_t)strMsgData.length(), xData, nPlayer);
		}

		static bool recieve_protobuf_message(const int nMsgID, const char* msg, const uint32_t nLen, google::protobuf::Message& xData, GUID& nPlayer)
		{
			Protocol::MsgBase xMsg;
			if (!xMsg.ParseFromArray(msg, nLen))
			{
				char szData[MAX_PATH] = { 0 };
				FGSPRINTF(szData, MAX_PATH, "Parse Message Failed from Packet to MsgBase, MessageID: %d\n", nMsgID);
#ifdef DEBUG
				std::cout << "--------------------" << szData << __FUNCTION__ << " " << __LINE__ << std::endl;
#endif // DEBUG

				return false;
			}

			if (!xData.ParseFromString(xMsg.msg_data()))
			{
				char szData[MAX_PATH] = { 0 };
				FGSPRINTF(szData, MAX_PATH, "Parse Message Failed from MsgData to ProtocolData, MessageID: %d\n", nMsgID);
#ifdef DEBUG
				std::cout << "--------------------" << szData << __FUNCTION__ << " " << __LINE__ << std::endl;
#endif // DEBUG

				return false;
			}

			nPlayer = PBToFG(xMsg.player_id());

			return true;
		}

		virtual int init_as_client(const char* ip, unsigned short port) = 0;
		virtual int init_as_server(unsigned int max_client_cnt, unsigned short port, int cpu_count = 4) = 0;
		virtual int expand_buffer_size(unsigned int size = 1024 * 1024 * 20) = 0;

		virtual bool register_net_message_handler(int id, const NET_MESSAGE_HANDLER_FUNCTOR_PTR& cb) = 0;
		virtual bool register_net_message_handler(const NET_MESSAGE_HANDLER_FUNCTOR_PTR& cb) = 0;
		virtual bool register_net_event_handler(const NET_EVENT_HANDLER_FUNCTOR_PTR& cb) = 0;

		virtual bool Execute() = 0;

		virtual bool send_msg_with_out_head(int16_t id, const std::string& msg, SOCK fd) = 0;
		virtual bool send_msg_to_all_client_with_out_head(int16_t id, const std::string& msg) = 0;
		virtual bool send_msg_with_out_head(const uint16_t nMsgID, const std::string& xData, const SOCK nSockIndex, const GUID id) = 0;

		virtual bool send_protobuf_message(const uint16_t nMsgID, const google::protobuf::Message& xData, const SOCK nSockIndex) = 0;
		virtual bool send_protobuf_message(const uint16_t nMsgID, const google::protobuf::Message& xData, const SOCK nSockIndex, const GUID nPlayer) = 0;
		virtual bool send_protobuf_message(const uint16_t nMsgID, const google::protobuf::Message& xData, const SOCK nSockIndex, const std::vector<GUID>* pClientIDList) = 0;
		virtual bool send_protobuf_message(const uint16_t nMsgID, const std::string& strData, const SOCK nSockIndex, const std::vector<GUID>* pClientIDList) = 0;
		virtual bool send_protobuf_message_to_all_clients(const uint16_t nMsgID, const google::protobuf::Message& xData) = 0;

		virtual INet* getNet() = 0;
	};
}
#endif
